import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { OperationMenuModule } from './operation-menu.module';
import { MenuItem } from '../core/types';

@Component({
  template: `
    <button (click)="modifyShowNum()">test</button>
    <lv-operation-menu
      [lvItemsFn]="commonItemsFn"
      [lvMaxShowNum]="showNum"
      [lvMenuText]="lvMenuText"
      [lvShowMode]="lvShowMode"
      (lvItemClick)="itemClick($event)"
      (lvOpenChange)="openChange($event)"
    ></lv-operation-menu>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
class TestOperationMenuComponent {
  showNum: number = 3;
  @Input() lvMenuText = 'test';
  @Input() lvShowMode = 'default';
  commonItems: MenuItem[];

  itemClick() {}
  openChange() {}
  modifyShowNum() {
    this.showNum = -1;
  }
  commonItemsFn() {
    this.commonItems = [
      { id: 'Edit', label: 'Edit' },
      { id: 'Delete', label: 'Delete', disabled: true },
      {
        id: 'File',
        label: 'File',
        icon: 'icon-task',
        items: [
          { id: 'File-Create', label: 'Create' },
          { id: 'File-Open', label: 'Open' },
          { id: 'File-Save', label: 'Save' },
        ],
      },
      {
        id: 'Do',
        label: 'Do',
        icon: 'icon-edit',
        items: [
          { id: 'Do-Undo', label: 'Undo' },
          { id: 'Do-Redo', label: 'Redo' },
        ],
      },
    ];

    return this.commonItems;
  }
}

describe('OperationMenuComponent', () => {
  beforeEach(
    waitForAsync(() => {
      TestBed.configureTestingModule({
        declarations: [TestOperationMenuComponent],
        imports: [OperationMenuModule, NoopAnimationsModule],
        teardown: { destroyAfterEach: false },
      }).compileComponents();
    })
  );

  describe('render', () => {
    let component: TestOperationMenuComponent;
    let fixture: ComponentFixture<TestOperationMenuComponent>;
    const renderComp = fakeAsync(para => {
      for (const [key, value] of Object.entries(para)) {
        component[key] = value;
      }
      fixture.detectChanges();
      tick(500);
      expect(fixture).toMatchSnapshot();
    });

    beforeEach(() => {
      fixture = TestBed.createComponent(TestOperationMenuComponent);
      component = fixture.componentInstance;
    });

    // 最大显示个数为负数渲染
    it('with lvMaxShowNum', fakeAsync(() => {
      fixture.detectChanges();
      tick(500);
      const button = fixture.nativeElement.querySelector('button');
      button.dispatchEvent(new Event('click'));
      fixture.detectChanges();
      tick(500);
      expect(fixture).toMatchSnapshot();
    }));

    // 操作菜单显示模式渲染
    it('with lvMenuText', () => {
      renderComp({ lvMenuText: 'test3' });
    });

    // 操作菜单显示模式渲染
    it('with lvShowMode', () => {
      renderComp({ lvShowMode: 'dropdown' });
    });
  });

  describe('work', () => {
    let component: TestOperationMenuComponent;
    let fixture: ComponentFixture<TestOperationMenuComponent>;

    beforeEach(() => {
      fixture = TestBed.createComponent(TestOperationMenuComponent);
      component = fixture.componentInstance;
      jest.spyOn(component, 'itemClick');
      jest.spyOn(component, 'openChange');
      fixture.autoDetectChanges();
    });

    // 打开下拉菜单能触发lvOpenChange回调，点击操作项能触发lvItemClick回调
    it('should work with lvItemClick and lvOpenChange', fakeAsync(() => {
      fixture.detectChanges();
      const dropdown = fixture.nativeElement.querySelector('.lv-operation-menu-dropdown');
      dropdown.dispatchEvent(new Event('click'));
      tick(500);
      fixture.detectChanges();
      expect(component.openChange).toBeCalled();

      const item = document.querySelector('.lv-dropdown-item');
      item.dispatchEvent(new Event('click'));
      tick(500);
      fixture.detectChanges();
      expect(component.itemClick).toBeCalled();
    }));
  });
});
